﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Diagnostics;

namespace WindowsFormsApplication1
{
    public partial class MapEditor : Form
    {
        Bitmap bmpMainBackground;   // 主背景图
        Bitmap bmpSecondaryBackground;   // 次背景图
        Bitmap bmpGrid;
        double fScale = 1.0;

        Point bmpDrawPos;
        Point bmpMoveStartPos;
        public TerrainLib terrainDialog;

        CMap mapData;
        CMap.CMapData MoveData;     // 按下F键，移动中的元素


        public MapEditor()
        {
            InitializeComponent();
            MouseWheel += new MouseEventHandler(MapEditor_MouseWheel);
            mapData = new CMap();
            if (terrainDialog == null)
            {
                terrainDialog = new TerrainLib();
            }
            pictureBox1.AllowDrop = true;
        }

        void MapEditor_MouseWheel(object sender, MouseEventArgs e)
        {
            if (bmpMainBackground == null)
                return;

            if (Keyboard.IsKeyDown(Keys.LControlKey))
            {
                int nTemp = e.Delta / 120 ;
                if( nTemp < 0 )
                {
                    fScale *= Math.Pow(0.9,-1 * nTemp);
                }
                else
                {
                    fScale *= Math.Pow(1.1, nTemp);
                }
                pictureBox1.Invalidate();
            }
        }

        private void NewMap_Click(object sender, EventArgs e)
        {
            bmpMainBackground = null;
            bmpSecondaryBackground = null;
            bmpGrid = null;
            pictureBox1.Invalidate();
        }

        private void BackgroundPicture1_Click(object sender, EventArgs e)
        {
            openPictureDialog.Filter = CONST.IMAGEFILTER;
            if( openPictureDialog.ShowDialog() != DialogResult.OK )
                return;

            if (ReadMainPic(openPictureDialog.FileName))
            {
                mapData.MainPicName = openPictureDialog.SafeFileName;
            }
        }

        private bool ReadMainPic(string picName)
        {
            bmpMainBackground = new Bitmap(picName);
            if (bmpMainBackground.Height % 16 != 0 ||
                 bmpMainBackground.Width % 16 != 0)
            {
                MessageBox.Show(CONST.BMPDIVIDEBY16);
                return false;
            }

            bmpGrid = new Bitmap(bmpMainBackground.Width, bmpMainBackground.Height);
            Graphics g = Graphics.FromImage(bmpGrid);
            g.Clear(Color.FromArgb(0, 0xFF, 0xFF, 0xFF));
            Pen pen = new Pen(Color.Black, 1);

            for (int i = 16; i <= bmpGrid.Width; i += 16)
            {
                g.DrawLine(pen, i, 0, i, bmpGrid.Height);
            }
            for (int i = 16; i <= bmpGrid.Height; i += 16)
            {
                g.DrawLine(pen, 0, i, bmpGrid.Width, i);
            }
            pictureBox1.Invalidate();
            return true;
        }

        private void BackgroundPicture2_Click(object sender, EventArgs e)
        {
            openPictureDialog.Filter = CONST.IMAGEFILTER ;
            openPictureDialog.ShowDialog();
            if ( openPictureDialog.ShowDialog() != DialogResult.OK )
            {
                return;
            }

            bmpSecondaryBackground = new Bitmap(openPictureDialog.OpenFile());
            pictureBox1.Invalidate();
        }

        private void pictureBox1_Paint(object sender, PaintEventArgs e)
        {
            if (bmpMainBackground == null)
                return;

            e.Graphics.DrawImage(bmpMainBackground, bmpDrawPos.X, bmpDrawPos.Y,
                Convert.ToSingle(bmpMainBackground.Width * fScale),
                Convert.ToSingle(bmpMainBackground.Height * fScale));

            if( ShowGrid.Checked && bmpGrid != null)
            {
                if (fScale > 0.5f)
                    e.Graphics.DrawImage(bmpGrid,bmpDrawPos.X, bmpDrawPos.Y,
                        Convert.ToSingle(bmpMainBackground.Width * fScale),
                        Convert.ToSingle(bmpMainBackground.Height * fScale));
            }

            foreach ( CMap.CMapData ii in mapData.mData )
            {
                if (ii == MoveData)
                {
                    e.Graphics.DrawImage(MoveData.data.bmpTerrainElement,
                        Convert.ToSingle(MoveData.Position.X ) + bmpDrawPos.X,
                        Convert.ToSingle(MoveData.Position.Y ) + bmpDrawPos.Y,
                        Convert.ToSingle(MoveData.data.bmpTerrainElement.Width * fScale),
                        Convert.ToSingle(MoveData.data.bmpTerrainElement.Height * fScale));
                }
                else
                {
                    e.Graphics.DrawImage(ii.data.bmpTerrainElement, 
                        Convert.ToSingle(ii.Position.X * fScale) + bmpDrawPos.X,
                        Convert.ToSingle(ii.Position.Y * fScale) + bmpDrawPos.Y,
                        Convert.ToSingle(ii.data.bmpTerrainElement.Width * fScale),
                        Convert.ToSingle(ii.data.bmpTerrainElement.Height * fScale));

                    if (ShowBlocks.Checked)
                    {

                        for (int i = 0; i < ii.data.bmpProperty.Width / 16; i++)
                        {
                            for (int j = 0; j < ii.data.bmpProperty.Height / 16; j++)
                            {
                                if (ii.data.mBlocks[i, j] == null)
                                {
                                    continue;
                                }
                                if (ii.data.mBlocks[i, j].BT != 0)
                                {
                                    double tempX = (ii.Position.X + i * 16) * fScale + bmpDrawPos.X;
                                    double tempY = (ii.Position.Y + j * 16) * fScale + bmpDrawPos.Y;
                                    e.Graphics.DrawImage(TerrainElementEditor.bmpBlock, 
                                        (float)tempX,
                                        (float)tempY,
                                        (float)(TerrainElementEditor.bmpBlock.Width * fScale),
                                        (float)(TerrainElementEditor.bmpBlock.Height * fScale)
                                        );
                                }
                            }
                        }

                        e.Graphics.DrawImage(ii.data.bmpProperty,
                            Convert.ToSingle(ii.Position.X * fScale) + bmpDrawPos.X,
                            Convert.ToSingle(ii.Position.Y * fScale) + bmpDrawPos.Y,
                            Convert.ToSingle(ii.data.bmpTerrainElement.Width * fScale),
                            Convert.ToSingle(ii.data.bmpTerrainElement.Height * fScale));


                    }
                }
            }
        }

        private void ShowGrid_Click(object sender, EventArgs e)
        {
            ShowGrid.Checked = !ShowGrid.Checked;
            pictureBox1.Invalidate();
        }

        private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
        {
            if (Keyboard.IsKeyDown(Keys.Space) && bmpMainBackground != null)
            {
                if (e.Button == MouseButtons.Left)
                {
                    this.Cursor = System.Windows.Forms.Cursors.SizeAll;
                    bmpDrawPos.X += e.Location.X - bmpMoveStartPos.X;
                    bmpDrawPos.Y += e.Location.Y - bmpMoveStartPos.Y;

                    bmpMoveStartPos = e.Location;

                    if (bmpDrawPos.X + bmpMainBackground.Width * fScale < pictureBox1.Width)
                    {
                        bmpDrawPos.X = pictureBox1.Width - Convert.ToInt32(bmpMainBackground.Width * fScale);
                    }
                    if (bmpDrawPos.Y + bmpMainBackground.Height * fScale < pictureBox1.Height)
                    {
                        bmpDrawPos.Y = pictureBox1.Height -  Convert.ToInt32(bmpMainBackground.Height * fScale);
                    }

                    if (bmpDrawPos.X > 0)
                        bmpDrawPos.X = 0;
                    if (bmpDrawPos.Y > 0)
                        bmpDrawPos.Y = 0;
                    pictureBox1.Invalidate();
                }
                else
                {
                    this.Cursor = System.Windows.Forms.Cursors.Default;
                }
            }
            else if (bmpMainBackground != null)
            {
                if (e.Button == MouseButtons.Left)
                {
                    if ( MoveData != null )
                    {
                        MoveData.Position.X = e.X;
                        MoveData.Position.Y = e.Y;

                        pictureBox1.Invalidate();
                    }
                }
            }
        }

        private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
        {
            if (Keyboard.IsKeyDown(Keys.Space))
            {
                // 空格+左键 ， 移动背景图
                if (e.Button == MouseButtons.Left)
                {
                    this.Cursor = System.Windows.Forms.Cursors.SizeAll;
                    bmpMoveStartPos = e.Location;
                }
            }
            else
            {
                if (Keyboard.IsKeyDown(Keys.F))
                {
                    if (e.Button == MouseButtons.Left)
                    {
                        // 选择这个点上的图片
                        foreach (CMap.CMapData i in mapData.mData)
                        {
                            // 计算图片框所在位置，大小
                            Rectangle rect = new Rectangle(
                            Convert.ToInt32((i.Position.X ) * fScale),
                            Convert.ToInt32((i.Position.Y ) * fScale),
                            Convert.ToInt32(i.data.bmpTerrainElement.Width * fScale),
                            Convert.ToInt32(i.data.bmpTerrainElement.Height * fScale));
                            int x = e.Location.X - bmpDrawPos.X;
                            int y = e.Location.Y - bmpDrawPos.Y;
                            if ( x >= rect.Left && x <= rect.Left + rect.Width &&
                                 y >= rect.Top && y <= rect.Top + rect.Height)
                            {
                                MoveData = i;
                                MoveData.Position = e.Location;
                                pictureBox1.Invalidate();
                                break;
                            }

                        }
                    }
                }
            }
        }

        private void ShowTerrainLib_Click(object sender, EventArgs e)
        {
            ShowTerrainLib.Checked = !ShowTerrainLib.Checked;

            if ( terrainDialog.IsDisposed )
            {
                terrainDialog = new TerrainLib();
            }
            terrainDialog.Visible = ShowTerrainLib.Checked;
        }

        public void UncheckMenuTerrainLib()
        {
            ShowTerrainLib.Checked = false;
        }

        private void Save_Click(object sender, EventArgs e)
        {
            if ( mapData.FileName == null )
            {
                saveFileDialog.Filter = CONST.XMLFILTER;
                if (saveFileDialog.ShowDialog() == DialogResult.OK)
                {
                    mapData.Write(saveFileDialog.FileName);
                }
            }
            else
            {
                mapData.Write();
            }
        }

        private void ReadMap_Click(object sender, EventArgs e)
        {
            openPictureDialog.Filter = "XML文件|*.xml";
            if (openPictureDialog.ShowDialog() == DialogResult.OK)
            {
                System.IO.FileInfo fi = new System.IO.FileInfo(openPictureDialog.FileName);
                
                if ( ! mapData.Read(fi.FullName) )
                {
                    return;
                }

                if (!ReadMainPic(
                    CONST.ROOTPATH + "\\" +
                    CONST.BACKGROUNDPICPATH + "\\" +
                    mapData.MainPicName))
                {
                    return;
                }
            }
        }

        private void SetRootPath_Click(object sender, EventArgs e)
        {
            SelectTerrainFolder.SelectedPath = CONST.ROOTPATH;
            if (SelectTerrainFolder.ShowDialog() == DialogResult.OK)
            {
                CONST.ROOTPATH = SelectTerrainFolder.SelectedPath;
            }
        }

        private void pictureBox1_DragEnter(object sender, DragEventArgs e)
        {
            // 拖拽进入
            if ( bmpMainBackground == null )
            {
                return;
            }
            e.Effect = DragDropEffects.Move;
            return;
        }

        private void pictureBox1_DragDrop(object sender, DragEventArgs e)
        {
            // 放下
            if (bmpMainBackground == null)
            {
                return;
            }

            try
            {
                String strItem = ((e.Data.GetData(DataFormats.Text))).ToString();
                strItem = strItem.Substring(strItem.IndexOf("{") + 1).Trim();
                strItem = strItem.Remove(strItem.Length - 1);

                CTerrainElement m = terrainDialog.terrainList.FindElement(strItem);
                if ( m != null)
                {
                    Point p = pictureBox1.PointToClient(new Point(e.X,e.Y));

                    // 对齐到网格
                    p.X = p.X - p.X % 16;
                    p.Y = p.Y - p.Y % 16;
                    
                    mapData.AddData(p, m);
                }

                pictureBox1.Invalidate();
                return;
            }
            catch (System.Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
            return;
        }

        private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                if ( MoveData != null)
                {
                    // 对齐到网格
                    int x = (int)(MoveData.Position.X / fScale);
                    int y = (int)(MoveData.Position.Y / fScale);

                    MoveData.Position.X = x - x % 16;
                    MoveData.Position.Y = y - y % 16;
                    MoveData = null;
                    pictureBox1.Invalidate();
                }
            }
        }

        private void ShowBlocks_Click(object sender, EventArgs e)
        {
            ShowBlocks.Checked = !ShowBlocks.Checked;
            pictureBox1.Invalidate();
        }
    }

    public abstract class Keyboard
    {
        [Flags]
        private enum KeyStates
        {
            None = 0,
            Down = 1,
            Toggled = 2
        }

        [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
        private static extern short GetKeyState(int keyCode);

        private static KeyStates GetKeyState(Keys key)
        {
            KeyStates state = KeyStates.None;

            short retVal = GetKeyState((int)key);

            //If the high-order bit is 1, the key is down
            //otherwise, it is up.
            if ((retVal & 0x8000) == 0x8000)
                state |= KeyStates.Down;

            //If the low-order bit is 1, the key is toggled.
            if ((retVal & 1) == 1)
                state |= KeyStates.Toggled;

            return state;
        }

        public static bool IsKeyDown(Keys key)
        {
            return KeyStates.Down == (GetKeyState(key) & KeyStates.Down);
        }

        public static bool IsKeyToggled(Keys key)
        {
            return KeyStates.Toggled == (GetKeyState(key) & KeyStates.Toggled);
        }
    }
}
